/* *****************************************************************************
 * JFab (http://code.google.com/p/jfab)
 * Copyright (c) 2011 JFab.org
 * Admin jfab@jeffreythompson.net
 *
 * See the file "LICENSE.txt" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * *****************************************************************************/

package org.jfab.core.io;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jfab.core.collection.CGFieldList;
import org.jfab.core.factory.StringFactory;
import org.jfab.core.factory.TypeReferenceSupport;
import org.jfab.core.formatter.Formatter;
import org.jfab.core.model.CGField;
import org.jfab.core.model.CGObject;

/**
 * Provides a partial implementation of a compilation unit writer.
 * 
 * @param <T> Code generator object type.
 */
public abstract class CGCompilationUnitWriter<T extends CGObject> implements
        CGWriter<T>
{
    /** Basic code generator. */
    private final BasicCodeGenerator _basicCodeGenerator;

    /** Field writer. */
    private final CGWriter<CGField> _fieldWriter;

    /** Code formatter. */
    private final Formatter _formatter;

    /** String factory. */
    private final StringFactory _stringFactory;

    /** Type reference support. */
    private final TypeReferenceSupport _typeReferenceSupport;

    /**
     * Construct this object with the given parameters.
     * 
     * @param typeReferenceSupport Type reference support.
     * @param stringFactory String factory.
     * @param basicCodeGenerator Basic code generator.
     * @param fieldWriter Field writer.
     * @param formatter Code formatter.
     */
    public CGCompilationUnitWriter(
            final TypeReferenceSupport typeReferenceSupport,
            final StringFactory stringFactory,
            final BasicCodeGenerator basicCodeGenerator,
            final CGWriter<CGField> fieldWriter, final Formatter formatter)
    {
        _typeReferenceSupport = typeReferenceSupport;
        _stringFactory = stringFactory;
        _basicCodeGenerator = basicCodeGenerator;
        _fieldWriter = fieldWriter;
        _formatter = formatter;
    }

    /**
     * Write the formatted content of the given string writer to the given
     * writer.
     * 
     * @param writer Writer to receive formatted content.
     * @param stringWriter String writer containing unformatted content.
     */
    protected void format(final Writer writer, final StringWriter stringWriter)
    {
        final Formatter formatter = getFormatter();
        final String result = formatter.format(stringWriter.toString());

        try
        {
            writer.write(result);
        }
        catch (final IOException e)
        {
            throw new JavaIOWriterException(e);
        }
    }

    /**
     * @return basicCodeGenerator
     */
    protected BasicCodeGenerator getBasicCodeGenerator()
    {
        return _basicCodeGenerator;
    }

    /**
     * @return the fieldWriter
     */
    protected CGWriter<CGField> getFieldWriter()
    {
        return _fieldWriter;
    }

    /**
     * @return the formatter
     */
    protected Formatter getFormatter()
    {
        return _formatter;
    }

    /**
     * @return stringFactory.
     */
    protected StringFactory getStringFactory()
    {
        return _stringFactory;
    }

    /**
     * @return the typeReferenceSupport
     */
    protected TypeReferenceSupport getTypeReferenceSupport()
    {
        return _typeReferenceSupport;
    }

    /**
     * Write fields.
     * 
     * @param writer Writer.
     * @param fields Fields.
     */
    protected void writeFields(final Writer writer, final CGFieldList fields)
    {
        if (CollectionUtils.isNotEmpty(fields))
        {
            final int size = fields.size();

            for (int i = 0; i < size; i++)
            {
                if (i > 0)
                {
                    getBasicCodeGenerator().writeBlankLine(writer);
                }

                getFieldWriter().write(writer, fields.get(i));
            }
        }
    }

    /**
     * @param writer Writer.
     * @param typeName Type name.
     */
    protected void writeImport(final Writer writer, final String typeName)
    {
        getBasicCodeGenerator().writeLine(writer, "import " + typeName + ";");
    }

    /**
     * @param writer Writer.
     * @param typeNames Type names.
     */
    protected void writeImports(final Writer writer,
            final Collection<String> typeNames)
    {
        for (final String typeName : typeNames)
        {
            writeImport(writer, typeName);
        }
    }

    /**
     * Write a package declaration.
     * 
     * @param writer Writer.
     * @param packageName Package name.
     */
    protected void writePackageDeclaration(final Writer writer,
            final String packageName)
    {
        if (StringUtils.isNotEmpty(packageName))
        {
            getBasicCodeGenerator().writeLine(writer,
                    "package " + packageName + ";");
        }
    }
}
